<?php
namespace addons\csmtable\library;

use think\App;
use think\Loader;
use addons\csmtable\library\CsmRequest;
use addons\csmtable\library\XLSXWriter;
use addons\csmtable\library\CsmTableUtils;
use think\Request;

/**
 * Excel下载任务管理
 *
 * @icon fa fa-circle-o
 */
class CsmgenerateTask
{
 
    private $xlstaskdao = null;
    private $excelmaxrecoredcount = null;
    private $controlpagesize = null;
    protected $uploadtmppath = RUNTIME_PATH . 'temp' . DS;

    public function __construct(){
        $this->xlstaskdao = new \app\admin\model\csmtable\Xlstask();
        $config = get_addon_config("csmtable");
        $this->excelmaxrecoredcount = (int)$config["excelmaxrecoredcount"];
        $this->controlpagesize = $config["controlpagesize"];
    }
    /**
     * excel item的下载任务
     * v2.2.5
     */
    public function index($id,$fileno,$offset)
    {
        set_time_limit(0);
        ini_set('display_errors', 'on');  

        $params = $this->getXlstaskParams($id);
        $columns = json_decode(CsmTableUtils::getParamValue($params, 'csmtable_columns'), true);
        
        // Excel处理
        if (true) {
            // Excel写入标题行
            $arrData = [];
            $arrDataCol = [];
            foreach ($columns as &$item) {
                $arrDataCol[] = &$item['title'];
            } 
            $arrData[] = $arrDataCol;
               
            $controlpage = 0;
            while(true){
                $offset2 = $this->controlpagesize*$controlpage + $offset;
                $limit = $this->controlpagesize;
                if(($this->controlpagesize*($controlpage+1)) > $this->excelmaxrecoredcount){
                    echo '=';
                    $limit = $this->excelmaxrecoredcount - $offset2;
                }
                $controlpage++;

                // 读取control数据
                $controlData = CsmTableUtils::callRemoteControl($params, $offset2, $limit);
                $datarows = &$controlData->getData()['rows'];
                //add by chensm@20200606 关联model, 比如格式如 ['admin'=>['id'=>1,'username'=>'admin]], v2.0.4
                //需要转换为column的格式  ['admin.id'=>1,'admin.username'=>'admin']
                foreach($datarows as $index=>&$row){
                    foreach($row as $k=>&$item){
                        if(is_array($item)){
                            foreach($item as $kk=>$vv){
                                $datarows[$index]["{$k}.{$kk}"] = $vv;
                            }
                        }
                    }
                }
                //2.1.10 在1.2.0版本下,关联下载为空的问题
                foreach($datarows as $index=>&$row){
                    if(is_object($row)){
                        foreach($row->getRelation() as $k=>&$item){
                            foreach($item->getData() as $kk=>$vv){
                                $datarows[$index]["{$k}.{$kk}"] = $vv;
                            }
                        }
                    }
                }
                
                // 读取id换取名称的数组
                $dsDatas = $this->getDataSourceDatas($columns, $datarows);

                // 写入Data数据
                foreach ($datarows as &$item) {
                    $arrDataCol = [];
                    foreach ($columns as &$column) {
                        
                        $vv = '';
                        if(isset($column['field']) && isset($item[$column['field']])){
                            $vv = $item[$column['field']];
                        }
                        
                        $arrDataCol[] = $this->_convertValueByColumn($column, $vv, $dsDatas);
                    }
                    $arrData[] = $arrDataCol;
                }
                //总记录数>excel总记录数,则说明要换个文件了
                if(($offset2+$limit)>=($this->excelmaxrecoredcount + $offset)){
                    break;
                }
                //2.1.10 excel读取速度优化,减少当记录数过少时会重复读取的问题 : 实际的获取的记录数<准备获取的记录数,说明已经完成读取
                if($limit>count($datarows)){
                    break;
                }
 
 
            }

            $filename = $this->saveToExcel($arrData, $id, $fileno);
            
 
            return $filename;
        }
    }

    private function saveToExcel(&$arrData, $id, $fileno)
    {
        $writer = new XLSXWriter();
        $writer->writeSheet($arrData);

        $filename = 'csmtable-excel-' . $id . '-' . time() . '-' . $fileno . '.xls';
        $filepath = &$this->uploadtmppath;
        $writer->writeToFile($filepath . $filename);

        return $filename;
    }

    /**
     * 将value根据table的options转换成文字
     */
    private function _convertValueByColumn(&$column, &$value, &$dsDatas)
    {
        $sr = '';
        if (isset($column['searchList']) && $column['searchList'] != null) {
            // searchlist类型的,将code转为name
            $searchList = $column['searchList'];
            // operate类型,字典数组,用逗号分隔
            if (isset($column['operate']) && $column['operate'] != null && $column['operate'] == 'FIND_IN_SET') {
                $ssarr = explode(",", $value);
                $sslabel = [];
                foreach ($ssarr as &$ssarrv) {
                    if (isset($searchList[$ssarrv])) {
                        $sslabel[] = $searchList[$ssarrv];
                    } else {
                        $sslabel[] = $ssarrv;
                    }
                }
                $sr = implode(',', $sslabel);
            } else {
                // 普通字典
                if (isset($searchList[$value])) {
                    $sr = $searchList[$value];
                }
            }
        } else if (isset($column['formatter']) && $column['formatter'] != null && $column['formatter'] == "Table.api.formatter.datetime") {
            // 时间型
            if ($value != null && $value != '') {
                //2.1.7 修复日期格式错误
                $sr = date('Y-m-d H:i:s', $value);
            }
        } else if (isset($column['datasource']) && $column['datasource'] != null && $column['datasource'] != "") {
            //chensm@20200626:支持一对多关联,用逗号分隔
            if (isset($dsDatas[$column['field']]) && $dsDatas[$column['field']] != null) {
                $dsDataitem = $dsDatas[$column['field']];
                if(stripos($value,",")===false){
                    if (isset($dsDataitem['ID#' . $value]) && $dsDataitem['ID#' . $value] != null) {
                        $sr = $dsDataitem['ID#' . $value];
                    }
                }else{  
                    $vvalue = explode(",",$value);
                    
                    $vtext = [];
                    foreach($vvalue as $iitem){
                        if (isset($dsDataitem['ID#' . $iitem]) && $dsDataitem['ID#' . $iitem] != null) {
                            $vtext[] = $dsDataitem['ID#' . $iitem];
                        }
                    }
                    $sr = implode(",",$vtext);
                }

            }
            if ($sr == null || $sr == '') {
                $sr = $value;
            }
            
        } else {
            $sr = $value;
        }
        return $sr;
    }

    private function getDataSourceDatas(&$columns, &$rows)
    {
        $sr = [];
        foreach ($columns as &$column) {
            if (isset($column['datasource']) && $column['datasource'] != null) {
                $datafield = null;
                if (isset($column['datafield']) && $column['datafield'] != null) {
                    $datafield = $column['datafield'];
                } else {
                    $datafield = 'name';
                }
                $ids = [];
                foreach ($rows as $item) {
                    $ids[] = $item[$column['field']];
                }

                //v2.2.5 修复admin账号的安全楼栋
                $datasdatasource_callremoteource = $column['datasource'];
                if($datasdatasource_callremoteource=="auth/admin"){
                    $datasdatasource_callremoteource = "csmtable/datasource/admin";
                }
                $im = CsmTableUtils::getInstanceAndMethod($datasdatasource_callremoteource);
                
                
                $alias = '';
                if(isset($column['datasourcealias']) && $column['datasourcealias']!=null && $column['datasourcealias']!=''){
                    $alias = $column['datasourcealias'].'.';
                }

                if ($im != null) {
                    $classname = $im[0];
                    $methodname = $im[1];

                    $request = CsmRequest::instance();
                    $request->setMethodReturn("isAjax", true);
                    $request->set('filter', '{"'.$alias.'id":"' . implode(',', $ids) . '"}');
                    $request->set('op', '{"'.$alias.'id":"in"}');
                    $request->set('sort', $alias.'id');
                    $request->set('order', 'desc');

                    // \app\admin\controller\auth\Admin;
                    $instance2 = new $classname($request);
                    $json2 = App::invokeMethod([
                        $instance2,
                        $methodname
                    ], null);

                    if ($json2 == null) {
                        break;
                    }

                    $datarows = &$json2->getData()['rows'];

                    $vvs = [];
                    foreach ($datarows as &$row) {
                        $vv = null;
                        if (isset($row[$datafield])) {
                            $vv = $row[$datafield];
                        } else {
                            $vv = $row->$datafield;
                        }

                        $vvs['ID#' . $row['id']] = $vv;
                    }
                    unset($json2);
                    unset($instance2);
                    $instance2 = null;
                }
                $sr[$column['field']] = $vvs;
            }
        }
        return $sr;
    }
 
    
    


    private function getXlstaskParams($id)
    {
        $xlstaskrow = $this->xlstaskdao->where('id', '=', $id)->find();
        if ($xlstaskrow == null) {
            return;
        }
        return json_decode($xlstaskrow->param, true);
    }

    // private function getParamValue(&$params, $key, $defaultvalue = null)
    // {
    //     $sr = null;
    //     if (isset($params[$key])) {
    //         $sr = $params[$key];
    //     }
    //     $sr = ($sr == null) ? $defaultvalue : $sr;
    //     return $sr;
    // }
    // private function callRemoteControl(&$params, $offset, $limit)
    // {
    //     $classname = str_replace('/', '\\', $this->getParamValue($params, 'csmtable_classname'));
    //     $methodname = $this->getParamValue($params, 'csmtable_methodname');
 
    //     $controller = null;
    //     if(true){
    //         $request = CsmRequest::instance(); 
    //         $onlyClassname = Loader::parseName(substr($classname,strrpos($classname,"\\")+1),0);
    //         $tt = substr($classname,0,strrpos($classname,"\\"));
    //         $tt = Loader::parseName(substr($tt,strrpos($tt,"\\")+1),1);
    //         $controller = "{$tt}.{$onlyClassname}";
    //     }
    //     $request->controller($controller);
    //     $request->action($methodname);


    //     $instance = new $classname($request);
    //     $request->set('search', $this->getParamValue($params, 'search'));
    //     $request->set('filter', $this->getParamValue($params, 'filter'));
    //     $request->set('op', $this->getParamValue($params, 'op'));
    //     $request->set('sort', $this->getParamValue($params, 'sort'));
    //     $request->set('order', $this->getParamValue($params, 'order'));
    //     $request->set("offset", $offset);
    //     $request->set("offset/d", $offset);//v2.1.8 修复在1.2.0.20201008_beta版本下导出数据记录数错误的问题
    //     $request->set('limit', $limit);
    //     $request->set('limit/d', $limit);//v2.1.8 修复在1.2.0.20201008_beta版本下导出数据记录数错误的问题
    //     $request->setMethodReturn("isAjax", true);
        
    //     //2.2.3 适配1.3.3版本，修复导出数据错乱的问题
    //     //修复了control分页使用paginate方法造成导出分页信息无法获取，原因是Paginator#getCurrentPage获取page是直接通过Request，而不是control的Request方法
    //     $page = $limit ? intval($offset / $limit) + 1 : 1;
    //     Request::instance()->get([config('paginate.var_page') => $page]);
         
    //     return App::invokeMethod([
    //         $instance,
    //         $methodname
    //     ], null);
    // }
}




 